/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
 * Description: mbuf_video_sender.cpp source file
 */
#include "decoded_mbuf_video_sender.h"

int32_t DecodedMbufVideoSender::InitGrp(void)
{
    GroupShareAttr Mattr = { 0 };
    GroupCfg grpcfg = { 0 };
    BuffCfg buffcfg = { 0 };
    int32_t devId = 0;
    int32_t ret;
    // 1024 1kb   32 GB
    grpcfg.maxMemSize = 1024 * 1024 * 32;
    Mattr.admin = 1;
    Mattr.alloc = 1;
    Mattr.write = 1;
    Mattr.read = 1;
    ret = halGrpAttach("DEFAULT_MEM_GROUP", 0);
    if (ret != HI_SUCCESS) {
        printf("manager halGrpAttach failed! ret(%d)\n", ret);
        return HI_FAILURE;
    }
    ret = halBuffInit(&buffcfg);
    if (ret != HI_SUCCESS) {
        printf("manager halBuffInit failed! ret(%d)\n", ret);
        return HI_FAILURE;
    }
    return HI_SUCCESS;
}

void DecodedMbufVideoSender::get_current_time_us(uint64_t &timeUs)
{
    timeval curTime;
    gettimeofday(&curTime, NULL);
    // 1000000: 将秒转换成微秒
    timeUs = (uint64_t)curTime.tv_sec * 1000000 + curTime.tv_usec;
}

bool DecodedMbufVideoSender::FillYuvAndSend(uint8_t *ptr, int32_t w, int32_t h)
{
    if (dataSkeleton == NULL || dataSkeleton == nullptr) {
        printf("dataSkeleton IS NULL \n");
        return false;
    }
    auto imagePub = dataSkeleton->cameraDecodedMbufEvent.Allocate();

    imagePub->CameraHeader.FrameId = frameID;
    imagePub->CameraHeader.Seq = 0;
    imagePub->FrameType = static_cast<decltype(imagePub->FrameType)>(Adsfi::HAF_IMAGE_YUV420SP_NV12_UINT8);
    imagePub->Width = w;
    imagePub->Height = h;
    size_t sizeInBytes = w * h * 3 / 2;
    imagePub->DataSize = sizeInBytes;
    uintptr_t imgdata {};
    cv::Mat YUV420NV12;
    (void)CopyToMbuf(imgdata, ptr, sizeInBytes);

    if (imgdata == reinterpret_cast<uintptr_t>(nullptr)) {
        return false;
    }
    imagePub->RawData = reinterpret_cast<rawBuffer *>(imgdata);
    auto t1 = std::chrono::steady_clock::now();
    lastTime = std::chrono::duration<float64_t, std::milli>(t1.time_since_epoch()).count();
    std::stringstream ss3;
    ss3 << std::fixed << lastTime;

    if (g_comPara.time.empty()) {
        timeval now;
        gettimeofday(&now, NULL);
        imagePub->CameraHeader.Stamp.Sec = now.tv_sec;
        imagePub->CameraHeader.Stamp.Nsec = now.tv_usec * 1000U;
    } else {
        time_t timeStamp = convertTimeStr2TimeStamp(g_comPara.time);
        auto t1 = std::chrono::high_resolution_clock::now();
        int64_t duration = (t1 - sec).count() / 1000000000.0;
        imagePub->CameraHeader.Stamp.Sec = timeStamp + duration;
        printf("timeStamp = %ld\n", timeStamp + duration);
    }

    dataSkeleton->cameraDecodedMbufEvent.Send(move(imagePub));

    const int32_t sleepTimeIntervalMs = 1000000;
    int32_t freq = atoi(g_comPara.frequency.c_str());
    if (freq) {
        usleep(sleepTimeIntervalMs / 30); // 30hz
    } else {
        int32_t sleepTime = sleepTimeIntervalMs / freq;
        usleep(sleepTime);
    }
    return true;
}

void DecodedMbufVideoSender::SaveYuvFileAclHost(hi_video_frame frame, uint8_t *outImageBuf, FILE * const fd,
    uint32_t chanId)
{
    uint8_t *addr = (uint8_t *)frame.virt_addr[0];
    uint32_t imageSize = frame.width * frame.height * 3 / 2;
    int32_t ret = HI_SUCCESS;
    uint32_t outWidthStride = frame.width_stride[0];
    uint32_t outHeightStride = frame.height_stride[0];
    if (g_run_mode == ACL_HOST) {
        if (outImageBuf == NULL) {
            return;
        }
        for (uint32_t i = 0; i < frame.height; i++) {
            ret = aclrtMemcpy(outImageBuf + i * frame.width, frame.width, addr + i * outWidthStride, frame.width,
                ACL_MEMCPY_DEVICE_TO_HOST);
            if (ret != ACL_SUCCESS) {
                aclrtFreeHost(outImageBuf);
                return;
            }
        }
        // 2: height的一半
        for (uint32_t i = 0; i < frame.height / 2; i++) {
            ret = aclrtMemcpy(outImageBuf + i * frame.width + frame.width * frame.height, frame.width,
                addr + i * outWidthStride + outWidthStride * outHeightStride, frame.width, ACL_MEMCPY_DEVICE_TO_HOST);
            if (ret != ACL_SUCCESS) {
                aclrtFreeHost(outImageBuf);
                return;
            }
        }
        FillYuvAndSend(outImageBuf, frame.width, frame.height);
#ifdef SAVE_SENDER_FILE
        fwrite(outImageBuf, 1, imageSize, fd);
#endif
        aclrtFreeHost(outImageBuf);
    }
    dealDecRunNode.chanId = chanId;
    dealDecRunNode.imageSize = imageSize;
    dealDecRunNode.outHeightStride = outHeightStride;
    dealDecRunNode.outWidthStride = outWidthStride;
    bool result = DealRunNode(addr, frame, fd);
    if (!result) {
        return;
    }
}

bool DecodedMbufVideoSender::DealRunNode(uint8_t *addr, hi_video_frame frame, FILE * const fd)
{
    if (g_run_mode != ACL_HOST) {
        uint8_t *outImageBuf = (uint8_t *)malloc(dealDecRunNode.imageSize);
        if (outImageBuf == NULL) {
            return false;
        }
        for (uint32_t i = 0; i < frame.height; i++) {
            memcpy_s(outImageBuf + i * frame.width, frame.width, addr + i * dealDecRunNode.outWidthStride, frame.width);
        }
        // 2: frame的高所占比例
        for (uint32_t i = 0; i < frame.height / 2; i++) {
            memcpy_s(outImageBuf + i * frame.width + frame.width * frame.height, frame.width,
                addr + i * dealDecRunNode.outWidthStride +
                dealDecRunNode.outWidthStride * dealDecRunNode.outHeightStride, frame.width);
        }
        FillYuvAndSend(outImageBuf, frame.width, frame.height);
#ifdef SAVE_SENDER_FILE
        fwrite(outImageBuf, 1, dealDecRunNode.imageSize, fd);
#endif
        free(outImageBuf);
    }
    return true;
}

bool DecodedMbufVideoSender::save_yuv_file(FILE *const fd, hi_video_frame frame, uint32_t chanId)
{
    uint8_t *addr = (uint8_t *)frame.virt_addr[0];
    uint32_t imageSize = frame.width * frame.height * 3 / 2;
    int32_t ret = HI_SUCCESS;
    uint8_t *outImageBuf = nullptr;
    uint32_t outWidthStride = frame.width_stride[0];
    uint32_t outHeightStride = frame.height_stride[0];
    printf("[%s][%d] Chn %u, addr = %lx \n", __FUNCTION__, __LINE__, chanId, (uint64_t)(uintptr_t)frame.virt_addr[0]);
    printf("[%s][%d] Chn %u, Width = %u \n", __FUNCTION__, __LINE__, chanId, frame.width);
    printf("[%s][%d] Chn %u, Height = %u \n", __FUNCTION__, __LINE__, chanId, frame.height);
    printf("[%s][%d] Chn %u, PixelFormat = %d \n", __FUNCTION__, __LINE__, chanId, frame.pixel_format);
    printf("[%s][%d] Chn %u, OutWidthStride = %u \n", __FUNCTION__, __LINE__, chanId, frame.width_stride[0]);
    printf("[%s][%d] Chn %u, OutHeightStride = %u \n", __FUNCTION__, __LINE__, chanId, frame.height_stride[1]);
    printf("[%s][%d] Chn %u, fileName = %s \n", __FUNCTION__, __LINE__, chanId, g_input_file_name);
    if (g_run_mode == ACL_HOST) {
        // malloc host memory
        ret = aclrtMallocHost((void **)&outImageBuf, imageSize);
        if (ret != ACL_SUCCESS) {
            return false;
        }
    }
    if ((frame.width == outWidthStride) && (frame.height == outHeightStride)) {
        if (g_run_mode == ACL_HOST) {
            ret = aclrtMemcpy(outImageBuf, imageSize, addr, imageSize, ACL_MEMCPY_DEVICE_TO_HOST);
            if (ret != ACL_SUCCESS) {
                return false;
            }
            FillYuvAndSend(outImageBuf, frame.width, frame.height);
#ifdef SAVE_SENDER_FILE
            fwrite(outImageBuf, 1, imageSize, fd);
#endif
            aclrtFreeHost(outImageBuf);
        } else {
            FillYuvAndSend(addr, frame.width, frame.height);
#ifdef SAVE_SENDER_FILE
            fwrite(addr, imageSize, 1, fd);
#endif
        }
    } else {
        SaveYuvFileAclHost(frame, outImageBuf, fd, chanId);
    }
    return true;
}

void DecodedMbufVideoSender::SaveRgbFileAclHost(hi_video_frame frame, uint8_t *outImageBuf, FILE * const fd,
    uint32_t chanId)
{
    uint8_t *addr = (uint8_t *)frame.virt_addr[0];
    uint32_t imageSize = frame.width * frame.height * 3;
    int32_t ret = HI_SUCCESS;
    uint32_t outWidthStride = frame.width_stride[0];
    uint32_t outHeightStride = frame.height_stride[0];
    if (g_run_mode == ACL_HOST) {
        for (uint32_t i = 0; i < frame.height; i++) {
            ret = aclrtMemcpy(outImageBuf + i * frame.width * frameWidthTriploid, frame.width * frameWidthTriploid,
                addr + i * outWidthStride, frame.width * frameWidthTriploid, ACL_MEMCPY_DEVICE_TO_HOST);
            if (ret != HI_SUCCESS) {
                aclrtFreeHost(outImageBuf);
                return;
            }
        }
        fwrite(outImageBuf, 1, imageSize, fd);
        aclrtFreeHost(outImageBuf);
    } else {
        uint8_t *outImageBuf = (uint8_t *)malloc(imageSize);
        if (outImageBuf == NULL) {
            return;
        }
        for (uint32_t i = 0; i < frame.height; i++) {
            memcpy_s(outImageBuf + i * frame.width * frameWidthTriploid, frame.width * frameWidthTriploid,
                addr + i * outWidthStride, frame.width * frameWidthTriploid);
        }
        fwrite(outImageBuf, 1, imageSize, fd);
        free(outImageBuf);
    }
    return;
}

bool DecodedMbufVideoSender::save_rgb_file(FILE *const fd, hi_video_frame frame, uint32_t chanId)
{
    uint8_t *addr = (uint8_t *)frame.virt_addr[0];
    uint32_t imageSize = frame.width * frame.height * 3;
    int32_t ret = HI_SUCCESS;
    uint8_t *outImageBuf = nullptr;
    uint32_t outWidthStride = frame.width_stride[0];
    uint32_t outHeightStride = frame.height_stride[0];
    printf("[%s][%d] Chn %u, addr = %lx \n", __FUNCTION__, __LINE__, chanId, (uint64_t)(uintptr_t)frame.virt_addr[0]);
    printf("[%s][%d] Chn %u, Width = %d \n", __FUNCTION__, __LINE__, chanId, frame.width);
    printf("[%s][%d] Chn %u, Height = %d \n", __FUNCTION__, __LINE__, chanId, frame.height);
    printf("[%s][%d] Chn %u, PixelFormat = %d \n", __FUNCTION__, __LINE__, chanId, frame.pixel_format);
    printf("[%s][%d] Chn %u, OutWidthStride = %d \n", __FUNCTION__, __LINE__, chanId, frame.width_stride[0]);
    printf("[%s][%d] Chn %u, OutHeightStride = %d \n", __FUNCTION__, __LINE__, chanId, frame.height_stride[0]);
    if (g_run_mode == ACL_HOST) {
        // malloc host memory
        ret = aclrtMallocHost((void **)&outImageBuf, imageSize);
        if (ret != ACL_SUCCESS) {
            return false;
        }
    }
    if (((frame.width * frameWidthTriploid) == outWidthStride) && (frame.height == outHeightStride)) {
        if (g_run_mode == ACL_HOST) {
            ret = aclrtMemcpy(outImageBuf, imageSize, addr, imageSize, ACL_MEMCPY_DEVICE_TO_HOST);
            if (ret != ACL_SUCCESS) {
                return false;
            }
            fwrite(outImageBuf, 1, imageSize, fd);
            aclrtFreeHost(outImageBuf);
        } else {
            fwrite(addr, imageSize, 1, fd);
        }
    } else {
        SaveRgbFileAclHost(frame, outImageBuf, fd, chanId);
    }
    return true;
}

int32_t DecodedMbufVideoSender::vdec_create()
{
    int32_t ret = HI_SUCCESS;
    hi_vdec_chn_attr chnAttr[VDEC_MAX_CHN_NUM] {};
    hi_data_bit_width bitWidth = HI_DATA_BIT_WIDTH_8;
    // 10: 位宽
    if (g_in_bitwidth == 10) {
        bitWidth = HI_DATA_BIT_WIDTH_10;
    }
    for (uint32_t i = g_start_chn_num; i < g_start_chn_num + g_chn_num; i++) {
        if (g_in_format == 0) {
            chnAttr[i].type = HI_PT_H264;
        } else if (g_in_format == 1) {
            chnAttr[i].type = HI_PT_H265;
        }
        chnAttr[i].mode = HI_VDEC_SEND_MODE_FRAME;
        chnAttr[i].pic_width = g_in_width;
        chnAttr[i].pic_height = g_in_height;
        chnAttr[i].stream_buf_size = g_in_width * g_in_height * CN3 / CN2;
        chnAttr[i].frame_buf_cnt = g_ref_frame_num + g_display_frame_num + 1;
        hi_pic_buf_attr buf_attr{g_in_width, g_in_height, 0, bitWidth, HI_PIXEL_FORMAT_YUV_SEMIPLANAR_420,
            HI_COMPRESS_MODE_NONE};
        chnAttr[i].frame_buf_size = hi_vdec_get_pic_buf_size(chnAttr[i].type, &buf_attr);
        chnAttr[i].video_attr.ref_frame_num = g_ref_frame_num;
        chnAttr[i].video_attr.temporal_mvp_en = HI_TRUE;
        chnAttr[i].video_attr.tmv_buf_size = hi_vdec_get_tmv_buf_size(chnAttr[i].type, g_in_width, g_in_height);
        ret = hi_mpi_vdec_create_chn(i, &chnAttr[i]);
        if (ret != HI_SUCCESS) {
            return ret;
        }
        g_chan_create_state[i] = 1;
        ret = DealParam(i);
        if (ret != HI_SUCCESS) {
            return ret;
        }
    }
    return ret;
}

int32_t DecodedMbufVideoSender::DealParam(uint32_t i)
{
    int32_t ret = HI_SUCCESS;
    hi_vdec_chn_param chnParam;
    ret = hi_mpi_vdec_get_chn_param(i, &chnParam);
    if (ret != HI_SUCCESS) {
        return ret;
    }
    chnParam.video_param.dec_mode = HI_VIDEO_DEC_MODE_IPB;
    chnParam.video_param.compress_mode = HI_COMPRESS_MODE_HFBC;
    chnParam.video_param.video_format = HI_VIDEO_FORMAT_TILE_64x16;
    chnParam.display_frame_num = g_display_frame_num;
    if (g_output_order == 0) {
        chnParam.video_param.out_order = HI_VIDEO_OUT_ORDER_DISPLAY;
    } else {
        chnParam.video_param.out_order = HI_VIDEO_OUT_ORDER_DEC;
    }
    ret = hi_mpi_vdec_set_chn_param(i, &chnParam);
    if (ret != HI_SUCCESS) {
        return ret;
    }
    ret = hi_mpi_vdec_start_recv_stream(i);
    if (ret != HI_SUCCESS) {
        return ret;
    }
    return ret;
}

bool DecodedMbufVideoSender::vdec_reset_chn(uint32_t chanId)
{
    int32_t ret = HI_SUCCESS;
    hi_vdec_chn_status status {};
    ret = hi_mpi_vdec_stop_recv_stream(chanId);
    if (ret != HI_SUCCESS) {
        return false;
    }
    ret = hi_mpi_vdec_reset_chn(chanId);
    if (ret != HI_SUCCESS) {
        return false;
    }
    ret = hi_mpi_vdec_start_recv_stream(chanId);
    if (ret != HI_SUCCESS) {
        return false;
    }
    return true;
}

void DecodedMbufVideoSender::WaitVdecEnd()
{
    int32_t ret = HI_SUCCESS;
    int32_t waitTimes;
    int32_t sleepTime = 10000;
    hi_vdec_chn_status status {};
    hi_vdec_chn_status pre_status {};
    for (uint32_t i = g_start_chn_num; i < g_start_chn_num + g_chn_num; i++) {
        if (g_vdec_send_thread[i].joinable()) {
            g_vdec_send_thread[i].join();
        }
        g_vdec_send_thread[i] = {};

        waitTimes = 0;
        while (g_exit == 0) {
            ret = hi_mpi_vdec_query_status(i, &status);
            if (ret != HI_SUCCESS) {
                break;
            }
            if (((status.left_stream_bytes == 0) && (status.left_decoded_frames == 0)) || (g_get_exit_state[i] == 1)) {
                break;
            }
            if (status.left_decoded_frames == pre_status.left_decoded_frames) {
                waitTimes += sleepTime;
            } else {
                waitTimes = 0;
            }
            pre_status = status;
            usleep(sleepTime);
            if (waitTimes >= CN5000000) {
                vdec_reset_chn(i);
                break;
            }
        }
    }
    // 1000000: 1秒
    usleep(CN1000000);
    for (uint32_t i = g_start_chn_num; i < g_start_chn_num + g_chn_num; i++) {
        g_get_exit_state[i] = 1;
    }
    for (uint32_t i = g_start_chn_num; i < g_start_chn_num + g_chn_num; i++) {
        if (g_vdec_get_thread[i].joinable()) {
            g_vdec_get_thread[i].join();
        }
        g_vdec_get_thread[i] = {};
    }
}

void DecodedMbufVideoSender::VdecDestroy()
{
    int32_t ret = HI_SUCCESS;
    for (uint32_t i = g_start_chn_num; i < g_start_chn_num + g_chn_num; i++) {
        if (g_chan_create_state[i] == 1) {
            ret = hi_mpi_vdec_stop_recv_stream(i);
            if (ret != HI_SUCCESS) {
                printf("[%s][%d] Chn %u, hi_mpi_vdec_stop_recv_stream failed, ret = %x \n", __FUNCTION__, __LINE__, i,
                    ret);
            }
            ret = hi_mpi_vdec_destroy_chn(i);
            if (ret != HI_SUCCESS) {
                printf("[%s][%d] Chn %u, hi_mpi_vdec_destroy_chn failed, ret = %x \n", __FUNCTION__, __LINE__, i, ret);
            }
            release_outbuffer(i);
        }
    }
}

int32_t DecodedMbufVideoSender::create_send_stream_thread()
{
    int32_t ret = 0;
    uint32_t i = 0;
    g_vdec_send_thread[i] = {};
    g_send_thread_id[i] = i;
    g_vdec_send_thread[i] = std::thread(DecodedMbufVideoSender::SendStream, this);

    if (ret != 0) {
        g_vdec_send_thread[i] = {};
        return ret;
    }
    return ret;
}

int32_t DecodedMbufVideoSender::create_get_pic_thread()
{
    int32_t ret = 0;
    for (uint32_t i = g_start_chn_num; i < g_start_chn_num + g_chn_num; i++) {
        g_vdec_get_thread[i] = {};
        g_get_thread_id[i] = i;
        g_vdec_get_thread[i] = std::thread(DecodedMbufVideoSender::GetPic, this);

        if (ret != 0) {
            g_vdec_get_thread[i] = {};
            return ret;
        }
    }
    return ret;
}

void DecodedMbufVideoSender::UpdateOutPicInfo(hi_vdec_pic_info &outPicInfo, DecodedMbufVideoSender *thiz,
    uint32_t chanId, GetFrameMsg& frameMsg)
{
    outPicInfo.width = thiz->g_out_width;
    outPicInfo.height = thiz->g_out_height;
    outPicInfo.width_stride = thiz->g_out_width_stride;
    outPicInfo.height_stride = thiz->g_out_height_stride;
    outPicInfo.pixel_format = (hi_pixel_format)(frameMsg.outFormat);

    if ((thiz->g_render == 0) || (frameMsg.readCount % thiz->g_render == 0)) {
        int32_t mallocCount = 0;
        int32_t tryTimes = 20000;
        while (thiz->g_send_exit_state[chanId] == 0) {
            mallocCount++;
            (void)pthread_mutex_lock(&thiz->g_out_buffer_pool_lock[chanId]);
            if (thiz->g_out_buffer_pool[chanId].empty() == false) {
                frameMsg.outBuffer = thiz->g_out_buffer_pool[chanId].back();
                thiz->g_out_buffer_pool[chanId].pop_back();
                (void)pthread_mutex_unlock(&thiz->g_out_buffer_pool_lock[chanId]);
                break;
            } else {
                (void)pthread_mutex_unlock(&thiz->g_out_buffer_pool_lock[chanId]);
                usleep(CN1000);
            }
            if (mallocCount >= tryTimes) {
                printf("[%s][%d] Chn %u DvppMalloc From Pool Failed, Try again \n", __FUNCTION__, __LINE__, chanId);
                mallocCount = 0;
            }
        }
        frameMsg.stream.need_display = HI_TRUE;
        outPicInfo.vir_addr = (uint64_t)frameMsg.outBuffer;
        outPicInfo.buffer_size = frameMsg.outBufferSize;
    } else {
        frameMsg.stream.need_display = HI_FALSE;
        outPicInfo.vir_addr = 0;
        outPicInfo.buffer_size = 0;
    }
}

int32_t DecodedMbufVideoSender::DealSendFormat(DecodedMbufVideoSender *thiz, GetFrameMsg& frameMsg, FILE *fpInputFile)
{
    int32_t ret = HI_SUCCESS;
    void *outBuffer = NULL;
    uint32_t outBufferSize = 0;
    if ((thiz->g_out_format == 0) || (thiz->g_out_format == 1)) {
        // 3、2: 分别是宽高的占比
        outBufferSize = thiz->g_out_width_stride * thiz->g_out_height_stride * CN3 / CN2;
    } else if ((thiz->g_out_format == CN2) || (thiz->g_out_format == CN3)) {
         // 3、2:分别是确定输出格式
        outBufferSize = thiz->g_out_width_stride * thiz->g_out_height_stride;
    }
    for (uint32_t i = 0; i < thiz->g_alloc_num; i++) {
        ret = hi_mpi_dvpp_malloc(0, &outBuffer, outBufferSize);
        if (ret != HI_SUCCESS) {
            fclose(fpInputFile);
            free(frameMsg.inputFileBuf);
            if (thiz->g_run_mode == ACL_HOST) {
                hi_mpi_dvpp_free(frameMsg.dataDev);
            }
            return HI_FAILURE;
        }
        thiz->g_out_buffer_pool[frameMsg.chanId].push_back(outBuffer);
    }
    thiz->delay_exec(thiz->g_start_time, thiz->g_delay_time);
    thiz->get_current_time_us(thiz->g_vdec_start_time[frameMsg.chanId]);
    hi_pixel_format outFormat = HI_PIXEL_FORMAT_YUV_SEMIPLANAR_420;
    switch (thiz->g_out_format) {
        case 0:
            outFormat = HI_PIXEL_FORMAT_YUV_SEMIPLANAR_420;
            break;
        case 1:
            outFormat = HI_PIXEL_FORMAT_YVU_SEMIPLANAR_420;
            break;
        // 2: g_out_format的值
        case 2:
            outFormat = HI_PIXEL_FORMAT_RGB_888;
            break;
        // 3: g_out_format的值
        case 3:
            outFormat = HI_PIXEL_FORMAT_BGR_888;
            break;
        default:
            break;
    }
    frameMsg.outBuffer = outBuffer;
    frameMsg.outBufferSize = outBufferSize;
    frameMsg.outFormat = outFormat;
    return ret;
}

bool DecodedMbufVideoSender::DealDataDev(DecodedMbufVideoSender *thiz, uint8_t *dataDev, FILE *fpInputFile,
    GetFrameMsg& frameMsg)
{
    int32_t ret = HI_SUCCESS;
    if (thiz->g_run_mode == ACL_HOST) {
        ret = hi_mpi_dvpp_malloc(0, (void **)&dataDev, frameMsg.fileSize);
        if (ret != 0) {
            fclose(fpInputFile);
            free(frameMsg.inputFileBuf);
            return false;
        }
        ret = aclrtMemcpy(dataDev, frameMsg.fileSize, frameMsg.inputFileBuf, frameMsg.fileSize,
            ACL_MEMCPY_HOST_TO_DEVICE);
        if (ret != ACL_SUCCESS) {
            fclose(fpInputFile);
            free(frameMsg.inputFileBuf);
            hi_mpi_dvpp_free(dataDev);
            return false;
        }
    }
    return true;
}

void DecodedMbufVideoSender::DealInput(DecodedMbufVideoSender *thiz, InputMsg& inputMsg)
{
    aclError aclRet = aclrtSetCurrentContext(thiz->g_context);
    if (aclRet != ACL_SUCCESS) {
        inputMsg.ret = HI_FAILURE;
        return;
    }
    FILE *fpInputFile = NULL;
    fpInputFile = fopen(thiz->g_input_file_name, "rb");
    if (fpInputFile == NULL) {
        inputMsg.ret = HI_FAILURE;
        return;
    }
    uint32_t fileSize = 0;
    fseek(fpInputFile, 0L, SEEK_END);
    fileSize = ftell(fpInputFile);
    fseek(fpInputFile, 0L, SEEK_SET);
    uint8_t *inputFileBuf = NULL;
    inputFileBuf = (uint8_t *)malloc(fileSize);
    if (inputFileBuf == NULL) {
        fclose(fpInputFile);
        inputMsg.ret = HI_FAILURE;
        return;
    }
    uint32_t readLen = 0;
    readLen = fread(inputFileBuf, 1, fileSize, fpInputFile);
    if (readLen != fileSize) {
        fclose(fpInputFile);
        free(inputFileBuf);
        inputMsg.ret = HI_FAILURE;
        return;
    }
    inputMsg.fpInputFile = fpInputFile;
    inputMsg.aclRet = aclRet;
    inputMsg.fileSize = fileSize;
    inputMsg.inputFileBuf = inputFileBuf;
    inputMsg.readLen = readLen;
    inputMsg.ret = HI_SUCCESS;
}

void *DecodedMbufVideoSender::SendStream(DecodedMbufVideoSender *thiz)
{
    uint32_t sendFrameFailCnt = 0;
    prctl(PR_SET_NAME, "VdecSendStream", 0, 0, 0);
    uint32_t chanId = 0;

    int32_t ret = HI_SUCCESS;
    InputMsg inputMsg;
    DealInput(thiz, inputMsg);
    if (inputMsg.ret != HI_SUCCESS) {
        return (hi_void *)(HI_FAILURE);
    }

    FILE *fpInputFile = inputMsg.fpInputFile;
    uint8_t *inputFileBuf = inputMsg.inputFileBuf;
    uint32_t fileSize = inputMsg.fileSize;
    
    uint32_t frameCount = 0;
    hi_payload_type type = (thiz->g_in_format == 0) ? HI_PT_H264 : HI_PT_H265;

    GetFrameMsg frameMsg;
    frameMsg.inputFileBuf = inputFileBuf;
    frameMsg.fileSize = fileSize;

    uint8_t *dataDev = HI_NULL;
    bool bRet = DealDataDev(thiz, dataDev, fpInputFile, frameMsg);
    if (!bRet) {
        return (void *)HI_FAILURE;
    }

    inputFileBuf = frameMsg.inputFileBuf;

    frameMsg.chanId = chanId;
    frameMsg.inputFileBuf = inputFileBuf;
    frameMsg.frameCount = &frameCount;
    frameMsg.fileSize = fileSize;
    frameMsg.type = type;
    frameMsg.dataDev = dataDev;
    thiz->GetEveryFrame(frameMsg);

    ret = DealSendFormat(thiz, frameMsg, fpInputFile);
    if (ret != HI_SUCCESS) {
        return (void *)(HI_FAILURE);
    }

    hi_vdec_stream stream;
    hi_vdec_pic_info outPicInfo;

    frameMsg.stream = stream;
    frameMsg.chanId = chanId;

    uint32_t readCount = 0;
    uint64_t currentSendTime = 0;
    uint64_t lastSendTime = 0;
    uint32_t circleTimes = 0;
    int32_t timeOut = CN1000;
    thiz->get_current_time_us(currentSendTime);

    while (1) {
        if (thiz->g_send_exit_state[chanId] == 1) {
            break;
        }
        stream.pts = currentSendTime + thiz->g_send_interval;
        stream.addr = thiz->g_frame_addr[chanId][readCount];
        stream.len = thiz->g_frame_len[chanId][readCount];
        stream.end_of_frame = HI_TRUE;
        stream.end_of_stream = HI_FALSE;
        frameMsg.stream = stream;
        frameMsg.readCount = readCount;
        UpdateOutPicInfo(outPicInfo, thiz, chanId, frameMsg);
        stream = frameMsg.stream;

        readCount = (readCount + 1) % frameCount;
        if (readCount == 0) {
            circleTimes++;
        }
        thiz->get_current_time_us(currentSendTime);
        if ((currentSendTime - lastSendTime) < thiz->g_send_interval) {
            usleep(thiz->g_send_interval - (currentSendTime - lastSendTime));
        }
        thiz->get_current_time_us(lastSendTime);
        do {
            sendFrameFailCnt++;
            ret = hi_mpi_vdec_send_stream(chanId, &stream, &outPicInfo, timeOut);
            if (sendFrameFailCnt > CN30) {
                thiz->vdec_reset_chn(chanId);
                sendFrameFailCnt = 0;
                break;
            }
        } while (ret == HI_ERR_VDEC_BUF_FULL);
        if (ret != HI_SUCCESS) {
            break;
        } else {
            sendFrameFailCnt = 0;
            if ((thiz->g_send_times != 0) && (circleTimes >= thiz->g_send_times)) {
                break;
            }
        }
    }
    stream.addr = NULL;
    stream.len = 0;
    stream.end_of_frame = HI_FALSE;
    stream.end_of_stream = HI_TRUE;
    outPicInfo.vir_addr = 0;
    outPicInfo.buffer_size = 0;
    hi_mpi_vdec_send_stream(chanId, &stream, &outPicInfo, -1);
    fclose(fpInputFile);
    free(inputFileBuf);
    if (thiz->g_run_mode == ACL_HOST) {
        hi_mpi_dvpp_free(dataDev);
    }
    return (hi_void *)HI_SUCCESS;
}

void DecodedMbufVideoSender::GetPicHost(hi_video_frame_info& frame, DecodedMbufVideoSender *thiz,
    uint32_t& chanId, hi_vdec_stream& stream, int32_t& writeFileCnt)
{
    int32_t ret = HI_SUCCESS;
    FILE *fp = NULL;
    char saveFileName[256];
    ret = snprintf_s(saveFileName, sizeof(saveFileName), sizeof(saveFileName) - 1, "%s_chn%u_%d",
        thiz->g_output_file_name, chanId, writeFileCnt);
    if (ret <= 0) {
#ifdef IN_GITE
        thiz->g_get_exit_state[chanId] = 1;
#endif
        return;
    }
    if ((frame.v_frame.pixel_format == HI_PIXEL_FORMAT_YUV_SEMIPLANAR_420) ||
        (frame.v_frame.pixel_format == HI_PIXEL_FORMAT_YVU_SEMIPLANAR_420)) {
        thiz->save_yuv_file(thiz->fp_yuv, frame.v_frame, chanId);
    } else if ((frame.v_frame.pixel_format == HI_PIXEL_FORMAT_RGB_888) ||
        (frame.v_frame.pixel_format == HI_PIXEL_FORMAT_BGR_888)) {
        thiz->save_rgb_file(fp, frame.v_frame, chanId);
    }
    writeFileCnt++;
}

void *DecodedMbufVideoSender::GetPic(DecodedMbufVideoSender *thiz)
{
    prctl(PR_SET_NAME, "VdecGetPic", 0, 0, 0);
    uint32_t chanId = 0;
    aclError aclRet = aclrtSetCurrentContext(thiz->g_context);
    if (aclRet != ACL_SUCCESS) {
        thiz->g_get_exit_state[chanId] = 1;
        return (void *)(HI_FAILURE);
    }
    int32_t ret = HI_SUCCESS;
    hi_video_frame_info frame;
    hi_vdec_stream stream;
    int32_t decResult = 0;
    void *outputBuffer = NULL;
    int32_t successCnt = 0;
    int32_t failCnt = 0;
    int32_t timeOut = CN1000;
    int32_t writeFileCnt = 1;
    hi_vdec_supplement_info stSupplement {};
    while (1) {
        if (thiz->g_get_exit_state[chanId] == 1) {
            break;
        }
        ret = hi_mpi_vdec_get_frame(chanId, &frame, &stSupplement, &stream, timeOut);
        if (ret == HI_SUCCESS) {
            thiz->get_current_time_us(thiz->g_vdec_end_time[chanId]);
            outputBuffer = (void *)frame.v_frame.virt_addr[0];
            decResult = frame.v_frame.frame_flag;
            DealDecResult(decResult, successCnt, chanId, failCnt);

            thiz->g_vdec_get_frame_cnt[chanId] = successCnt + failCnt;
            if ((thiz->g_is_write_file == 1) && (decResult == 0) && (outputBuffer != NULL) &&
                (stream.need_display == HI_TRUE)) {
                GetPicHost(frame, thiz, chanId, stream, writeFileCnt);
            }
            if (outputBuffer != NULL) {
                (void)pthread_mutex_lock(&thiz->g_out_buffer_pool_lock[chanId]);
                thiz->g_out_buffer_pool[chanId].push_back(outputBuffer);
                (void)pthread_mutex_unlock(&thiz->g_out_buffer_pool_lock[chanId]);
            }
            ret = hi_mpi_vdec_release_frame(chanId, &frame);
            if (ret != HI_SUCCESS) {
                printf("[%s][%d] Chn %u hi_mpi_vdec_release_frame Fail,Error Code = %x \n", __FUNCTION__, __LINE__,
                    chanId, ret);
            }
        } else {
            usleep(500); // 当前线程休眠500微秒
        }
    }
    return (void *)HI_SUCCESS;
}

void DecodedMbufVideoSender::DealDecResult(int32_t& decResult, int32_t& successCnt, uint32_t& chanId, int32_t& failCnt)
{
    if (decResult == 0) {
        successCnt++;
        printf("[%s][%d] Chn %u GetFrame success, Decode success[%d] \n", __FUNCTION__, __LINE__, chanId, successCnt);
    } else if (decResult == 1) {
        failCnt++;
        printf("[%s][%d] Chn %u GetFrame success, Decode fail[%d] \n", __FUNCTION__, __LINE__, chanId, failCnt);
    } else if (decResult == CN2) { // 2: 数据帧的标志
        printf("[%s][%d] Chn %u GetFrame success, No Picture \n", __FUNCTION__, __LINE__, chanId);
    } else if (decResult == CN3) { // 3: 数据帧的标志
        failCnt++;
        printf("[%s][%d] Chn %u GetFrame success, RefFrame Num Error[%d] \n", __FUNCTION__, __LINE__, chanId, failCnt);
    } else if (decResult == CN4) { // 4: 数据帧的标志
        failCnt++;
        printf("[%s][%d] Chn %u GetFrame success, RefFrame Size Error[%d] \n", __FUNCTION__, __LINE__, chanId, failCnt);
    }
}

void DecodedMbufVideoSender::GetFrameHost(int32_t& i, int32_t& readLen, uint8_t *bufPointer,
    bool& isFindStart, bool& isFindEnd)
{
    // 8: 字节
    for (i = 0; i < readLen - CN8; i++) {
        // 3: 将指针移动3个字节
        int32_t tmp = bufPointer[i + CN3] & 0x1F;
        if ((bufPointer[i] == 0) && (bufPointer[i + 1] == 0) && (bufPointer[i + CN2] == 1) && // 2：将指针移动2个字节
            (((tmp == 0x5 || tmp == 0x1) && ((bufPointer[i + CN4] & 0x80) == 0x80)) || // 4：将指针移动4个字节
            (tmp == CN20 && (bufPointer[i + CN7] & 0x80) == 0x80))) { // 7: 将指针移动7个字节，20：ASCII码值
            isFindStart = true;
            i += CN8; // 8: 字节
            break;
        }
    }
    // 8：字节
    for (; i < readLen - CN8; i++) {
        int32_t tmp = bufPointer[i + CN3] & 0x1F; // 3: 将指针移动3个字节
        if ((bufPointer[i] == 0) && (bufPointer[i + 1] == 0) && (bufPointer[i + CN2] == 1) && // 2：将指针移动2个字节
            ((tmp == CN15) || (tmp == CN7) || (tmp == CN8) || (tmp == CN6) || // 6、7、8、15：ASCII码值
            ((tmp == CN5 || tmp == 1) &&
            ((bufPointer[i + CN4] & 0x80) == 0x80)) || // 5：ASCII码值，4：将指针移动4个字节
            (tmp == CN20 && (bufPointer[i + CN7] & 0x80) == 0x80))) { // 7: 将指针移动7个字节，20： ASCII码值
            isFindEnd = true;
            break;
        }
    }
    if (i > 0) {
        readLen = i;
    }
    if (!isFindStart) {
        printf("can not find h264 start code! readLen %d\n", readLen);
    }
    if (!isFindEnd) {
        readLen = i + CN8; // 8: 字节
    }
}

void DecodedMbufVideoSender::DealGetFrameHost(int32_t& i, int32_t& readLen, uint8_t *bufPointer,
    bool& isFindStart, bool& isFindEnd)
{
    bool isNewPic = false;
    // 6: 字节
    for (i = 0; i < readLen - CN6; i++) {
        uint32_t tmp = (bufPointer[i + CN3] & 0x7E) >> 1; // 3: 将指针移动3个字节
        if ((bufPointer[i + 0] == 0) && (bufPointer[i + 1] == 0) &&
            (bufPointer[i + CN2] == 1) && // 2: 将指针移动2个字节
            (tmp >= 0 && tmp <= CN21) && // 21: ASCII码值
            ((bufPointer[i + CN5] & 0x80) == 0x80)) { // 5: 将指针移动5个字节
            isNewPic = true;
        }
        if (isNewPic == true) {
            isFindStart = true;
            i += CN6; // 6: 字节
            break;
        }
    }

    // 6: 字节
    for (; i < readLen - CN6; i++) {
        uint32_t tmp = (bufPointer[i + CN3] & 0x7E) >> 1; // 3: 将指针移动3个字节
        isNewPic = ((bufPointer[i + 0] == 0) && (bufPointer[i + 1] == 0) &&
            (bufPointer[i + CN2] == 1) && // 2: 指针移动2个字节
            ((tmp == CN32) || (tmp == CN33) || // 32、3: ASCII码值
            (tmp == CN34) || (tmp == CN39) || (tmp == CN40) || // 34、39、40: ASCII码值
            ((tmp >= 0 && tmp <= CN21) && // 21: ASCII码值
            (bufPointer[i + CN5] & 0x80) == 0x80))); // 5: 将指针移动5个字节
        if (isNewPic == true) {
            isFindEnd = true;
            break;
        }
    }
    if (i > 0) {
        readLen = i;
    }
    if (!isFindStart) {
        printf("can not find h265 start code! readLen %d! \n", readLen);
    }
    if (!isFindEnd) {
        readLen = i + CN6; // 6: 字节
    }
}

void DecodedMbufVideoSender::GetEveryFrame(GetFrameMsg& frameMsg)
{
    int32_t chanId = frameMsg.chanId;
    uint8_t * const inputFileBuf = frameMsg.inputFileBuf;
    uint32_t * const frameCount = frameMsg.frameCount;
    uint32_t fileSize = frameMsg.fileSize;
    hi_payload_type type = frameMsg.type;
    uint8_t *dataDev = frameMsg.dataDev;
    int32_t i = 0;
    int32_t usedBytes = 0;
    int32_t readLen = 0;
    uint32_t count = 0;
    uint8_t *bufPointer = NULL;
    bool isFindStart = false;
    bool isFindEnd = false;

    while (1) {
        isFindStart = false;
        isFindEnd = false;
        bufPointer = inputFileBuf + usedBytes;
        readLen = fileSize - usedBytes;
        if (readLen <= 0) {
            break;
        }
        if (type == HI_PT_H264) {
            GetFrameHost(i, readLen, bufPointer, isFindStart, isFindEnd);
        } else if (type == HI_PT_H265) {
            DealGetFrameHost(i, readLen, bufPointer, isFindStart, isFindEnd);
        }
        if (g_run_mode == ACL_HOST) {
            g_frame_addr[chanId][count] = (bufPointer - inputFileBuf) + dataDev;
        } else {
            g_frame_addr[chanId][count] = bufPointer;
        }

        g_frame_len[chanId][count] = readLen;
        count++;
        usedBytes = usedBytes + readLen;
    }
    *frameCount = count;
}

void DecodedMbufVideoSender::delay_exec(uint64_t execTime, int32_t seconds)
{
    timeval currentTime;
    uint64_t tmpCurtime = 0;
    uint64_t secondToUs = CN1000000;
    gettimeofday(&currentTime, NULL);
    tmpCurtime = currentTime.tv_sec * secondToUs + currentTime.tv_usec;
    uint64_t nextExecTime = execTime + seconds * secondToUs;
    while (tmpCurtime < nextExecTime) {
        usleep(500); // 500:0.5ms
        gettimeofday(&currentTime, NULL);
        tmpCurtime = currentTime.tv_sec * secondToUs + currentTime.tv_usec;
    }
    return;
}

void DecodedMbufVideoSender::ShowDecodePerformance()
{
    double averFrameRate = 0;
    uint32_t chnNum = 0;
    uint64_t secondToUs = CN1000000;
    for (uint32_t i = g_start_chn_num; i < g_start_chn_num + g_chn_num; i++) {
        uint64_t diffTime = g_vdec_end_time[i] - g_vdec_start_time[i];
        if (diffTime == 0) {
            continue;
        }
        double actualFrameRate = ((double)g_vdec_get_frame_cnt[i] * secondToUs) / diffTime;
        averFrameRate += actualFrameRate;
        chnNum++;
    }
    averFrameRate = averFrameRate / chnNum;
    return;
}

int32_t DecodedMbufVideoSender::get_option(int32_t argc, char **argv)
{
    int32_t ret = HI_SUCCESS;
    while (1) {
        int32_t optionIndex = 0;
        option longOptions[] = {
            {"img_width", 1, 0, 'a'},
            {"img_height", 1, 0, 'b'},
            {"in_image_file", 1, 0, 'c'},
            {"in_format", 1, 0, 'd'},
            {"in_bitwidth", 1, 0, 'e'},
            {"out_width", 1, 0, 'f'},
            {"out_height", 1, 0, 'g'},
            {"out_image_file", 1, 0, 'h'},
            {"out_format", 1, 0, 'i'},
            {"width_stride", 1, 0, 'j'},
            {"height_stride", 1, 0, 'k'},
            {"write_file", 1, 0, 'l'},
            {"chn_num", 1, 0, 'm'},
            {"ref_frame_num", 1, 0, 'n'},
            {"dis_frame_num", 1, 0, 'o'},
            {"output_order", 1, 0, 'p'},
            {"send_times", 1, 0, 'q'},
            {"send_interval", 1, 0, 'r'},
            {"delay_time", 1, 0, 's'},
            {"alloc_num", 1, 0, 't'},
            {"start_chn", 1, 0, 'w'},
            {"render", 1, 0, 'v'}
        };
        int32_t parameter =
            getopt_long(argc, argv, "a:b:c:d:e:f:g:h:i:j:k:l:m:n:o:p:q:r:s:t:w:v:", longOptions, &optionIndex);
        if (parameter == -1) {
            break;
        }
        option_switch_al(parameter);
        option_switch_mv(parameter);
        if (ret != HI_SUCCESS) {
            return ret;
        }
    }
    return ret;
}

void DecodedMbufVideoSender::option_switch_al(int32_t parameter)
{
    switch (parameter) {
        case 'a':
            g_in_width = atoi(optarg);
            break;
        case 'b':
            g_in_height = atoi(optarg);
            break;
        case 'c':
            if (strcpy_s(g_input_file_name, sizeof(optarg) + 1, optarg) != 0) {
                std::cout<< "strcpy_s g_input_file_name failed, filename: " <<g_input_file_name <<std::endl;
            }
            break;
        case 'd':
            g_in_format = atoi(optarg);
            break;
        case 'e':
            g_in_bitwidth = atoi(optarg);
            break;
        case 'f':
            g_out_width = atoi(optarg);
            break;
        case 'g':
            g_out_height = atoi(optarg);
            break;
        case 'h':
            if (strcpy_s(g_output_file_name, sizeof(optarg) + 1, optarg) != 0) {
                std::cout<< "strcpy_s g_output_file_name failed, filename: " <<g_output_file_name <<std::endl;
            }
            break;
        case 'i':
            g_out_format = atoi(optarg);
            break;
        case 'j':
            g_out_width_stride = atoi(optarg);
            break;
        case 'k':
            g_out_height_stride = atoi(optarg);
            break;
        case 'l':
            g_is_write_file = atoi(optarg);
            break;
        default:
            printf("this is default! \n");
            break;
    }
}

void DecodedMbufVideoSender::option_switch_mv(int32_t parameter)
{
    switch (parameter) {
        case 'm':
            g_chn_num = atoi(optarg);
            break;
        case 'n':
            g_ref_frame_num = atoi(optarg);
            break;
        case 'o':
            g_display_frame_num = atoi(optarg);
            break;
        case 'p':
            g_output_order = atoi(optarg);
            break;
        case 'q':
            g_send_times = atoi(optarg);
            break;
        case 'r':
            g_send_interval = atoi(optarg);
            break;
        case 's':
            g_delay_time = atoi(optarg);
            break;
        case 't':
            g_alloc_num = atoi(optarg);
            break;
        case 'w':
            g_start_chn_num = atoi(optarg);
            break;
        case 'v':
            g_render = atoi(optarg);
            break;
        default:
            printf("this is default! \n");
            break;
    }
}

void DecodedMbufVideoSender::CheckOptionFormat()
{
    // 4096、128：输入内容的宽
    if ((g_in_width > CN4096) || (g_in_width < CN128)) {
        printf("[%s][%d] input file width is invalid, width = %u \n", __FUNCTION__, __LINE__, g_in_width);
        return (void)HI_FAILURE;
    }
    // 4096、128：输入内容的高
    if ((g_in_height > CN4096) || (g_in_height < CN128)) {
        printf("[%s][%d] input file height is invalid, height = %u \n", __FUNCTION__, __LINE__, g_in_height);
        return (void)HI_FAILURE;
    }
    if ((g_in_format != 0) && (g_in_format != 1)) {
        printf("[%s][%d] input format is invalid, format = %u \n", __FUNCTION__, __LINE__, g_in_format);
        return (void)HI_FAILURE;
    }
    // 8、10：输入内容的位宽
    if ((g_in_bitwidth != CN8) && (g_in_bitwidth != CN10)) {
        printf("[%s][%d] input bitwidth is invalid, bitwidth = %u \n", __FUNCTION__, __LINE__, g_in_bitwidth);
        return (void)HI_FAILURE;
    }
    // 4096、10：输入内容的宽
    if ((g_out_width != 0) && ((g_out_width > CN4096) || (g_out_width < CN10))) {
        printf("[%s][%d] output width is invalid, width = %u \n", __FUNCTION__, __LINE__, g_out_width);
        return (void)HI_FAILURE;
    }
    // 4096、6：输入内容的高
    if ((g_out_height != 0) && ((g_out_height > CN4096) || (g_out_height < CN6))) {
        printf("[%s][%d] output height is invalid, height = %u \n", __FUNCTION__, __LINE__, g_out_height);
        return (void)HI_FAILURE;
    }
    // 3：输出信息的格式
    if (g_out_format > CN3) {
        printf("[%s][%d] output format is invalid, format = %u \n", __FUNCTION__, __LINE__, g_out_format);
        return (void)HI_FAILURE;
    }
    // 16：步长，输入数据的宽度要是16的整数倍，32：输出的数据宽
    if ((g_out_width_stride % CN16 != 0) || (g_out_width_stride < g_out_width) || (g_out_width_stride < CN32)) {
        return (void)HI_FAILURE;
    }
    // 2、3：输出信息的格式，3：宽度占比
    if (((g_out_format == CN2) || (g_out_format == CN3)) && (g_out_width_stride < g_out_width * CN3)) {
        return (void)HI_FAILURE;
    }
    // 2：高度占比
    if (((g_out_height_stride % CN2 != 0) && ((g_out_format == 0) || (g_out_format == 1))) ||
        (g_out_height_stride < g_out_height)) {
        return (void)HI_FAILURE;
    }
}

int32_t DecodedMbufVideoSender::check_option()
{
    // 输出内容的格式
    CheckOptionFormat();
    if (g_is_write_file > 1) {
        return HI_FAILURE;
    }
    // 96：chan num
    if ((g_chn_num > CN96) || (g_chn_num < 1)) {
        printf("[%s][%d] chan num is invalid, chan num = %u \n", __FUNCTION__, __LINE__, g_chn_num);
        return HI_FAILURE;
    }
    // 16: RefFrame num
    if (g_ref_frame_num > CN16) {
        printf("[%s][%d] RefFrame num is invalid, RefFrame num = %u \n", __FUNCTION__, __LINE__, g_ref_frame_num);
        return HI_FAILURE;
    }
    // 16：显示的帧数
    if (g_display_frame_num > CN16) {
        return HI_FAILURE;
    }
    // 2：输出顺序
    if (g_output_order > CN2) {
        printf("[%s][%d] output order is invalid, output order = %u \n", __FUNCTION__, __LINE__, g_output_order);
        return HI_FAILURE;
    }
    if (g_start_chn_num + g_chn_num >= VDEC_MAX_CHN_NUM) {
        printf("[%s][%d] start chan num is invalid, start chan num = %u \n", __FUNCTION__, __LINE__, g_start_chn_num);
        return HI_FAILURE;
    }
    return HI_SUCCESS;
}

void DecodedMbufVideoSender::PrintParameter()
{
    printf("\n/****************************Vdec Parameter****************************/\n");
    printf("InputFileName: %s \n", g_input_file_name);
    printf("OutputFileName: %s \n", g_output_file_name);
    printf("Width: %u \n", g_in_width);
    printf("Height: %u \n", g_in_height);
    printf("InFormat: %u \n", g_in_format);
    printf("Bitwidth: %u \n", g_in_bitwidth);
    printf("OutWidth: %u \n", g_out_width);
    printf("OutHeight: %u \n", g_out_height);
    printf("OutFormat: %u \n", g_out_format);
    printf("OutWidthStride: %u \n", g_out_width_stride);
    printf("OutHeightStride: %u \n", g_out_height_stride);
    printf("ChnNum: %u \n", g_chn_num);
    printf("RefFrameNum: %u \n", g_ref_frame_num);
    printf("DisplayFrameNum: %u \n", g_display_frame_num);
    printf("OutPutOrder: %u \n", g_output_order);
    printf("SendTimes: %u \n", g_send_times);
    printf("SendInterval: %u \n", g_send_interval);
    printf("DelayTime: %u \n", g_delay_time);
    printf("AllocNum: %u \n", g_alloc_num);
    printf("StartChnNum: %u \n", g_start_chn_num);
    printf("Render: %u \n", g_render);
    printf("/**********************************************************************/\n");
}

void DecodedMbufVideoSender::vdec_handle_signal(int32_t signo)
{
    for (int32_t i = g_start_chn_num; i < g_start_chn_num + g_chn_num; i++) {
        g_send_exit_state[i] = 1;
    }
    g_exit = 1;
}

void DecodedMbufVideoSender::InitOutbufferLock()
{
    for (uint32_t i = g_start_chn_num; i < g_start_chn_num + g_chn_num; i++) {
        pthread_mutex_init(&g_out_buffer_pool_lock[i], NULL);
    }
}

void DecodedMbufVideoSender::DestroyOutbufferLock()
{
    for (uint32_t i = g_start_chn_num; i < g_start_chn_num + g_chn_num; i++) {
        pthread_mutex_destroy(&g_out_buffer_pool_lock[i]);
    }
}

void DecodedMbufVideoSender::release_outbuffer(uint32_t chanId)
{
    void *outBuffer = NULL;
    while (g_out_buffer_pool[chanId].empty() == false) {
        outBuffer = g_out_buffer_pool[chanId].back();
        g_out_buffer_pool[chanId].pop_back();
        hi_mpi_dvpp_free(outBuffer);
    }
}

void DecodedMbufVideoSender::GetStartTime()
{
    timeval currentTime;
    gettimeofday(&currentTime, NULL);
    g_start_time = currentTime.tv_sec * sleepTimeIntervalMs + currentTime.tv_usec;
}

int32_t DecodedMbufVideoSender::hi_dvpp_init()
{
    int32_t s32Ret = ACL_SUCCESS;
    aclError aclRet = aclInit(NULL);
    // 100002：重复初始化或重复加载
    if ((aclRet != ACL_SUCCESS) && (aclRet != 100002)) {
        return HI_FAILURE;
    }
    aclRet = aclrtSetDevice(0);
    if (aclRet != ACL_SUCCESS) {
        aclFinalize();
        return HI_FAILURE;
    }
    aclRet = aclrtCreateContext(&g_context, 0);
    if (aclRet != ACL_SUCCESS) {
        aclrtResetDevice(0);
        aclFinalize();
        return HI_FAILURE;
    }
    int32_t ret = hi_mpi_sys_init();
    if (ret != HI_SUCCESS) {
#ifdef IN_GITE
        aclrtDestroyContext(g_context);
#endif
        aclrtResetDevice(0);
        aclFinalize();
        return HI_FAILURE;
    }
    aclRet = aclrtGetRunMode(&g_run_mode);
    if (aclRet != HI_SUCCESS) {
        hi_mpi_sys_exit();
        aclrtDestroyContext(g_context);
        aclrtResetDevice(0);
        aclFinalize();
        return HI_FAILURE;
    }
    return HI_SUCCESS;
}

int32_t DecodedMbufVideoSender::HiDvppDeinit()
{
    int32_t ret = hi_mpi_sys_exit();
    if (ret != HI_SUCCESS) {
        printf("[%s][%d] hi_mpi_sys_exit failed, error code = %x. \n", __FUNCTION__, __LINE__, ret);
        return ret;
    }
    aclError aclRet = aclrtDestroyContext(g_context);
    if (aclRet != ACL_SUCCESS) {
        printf("[%s][%d] aclrtDestroyContext failed, error code = %d. \n", __FUNCTION__, __LINE__, aclRet);
        return aclRet;
    }
    aclRet = aclrtResetDevice(0);
    if (aclRet != ACL_SUCCESS) {
        printf("[%s][%d] aclrtResetDevice 0 failed, error code = %d. \n", __FUNCTION__, __LINE__, aclRet);
        return aclRet;
    }
    aclRet = aclFinalize();
    // 100037：重复去初始化
    if ((aclRet != ACL_SUCCESS) && (aclRet != 100037)) {
        printf("[%s][%d] aclFinalize failed, error code = %d. \n", __FUNCTION__, __LINE__, aclRet);
    }
    return aclRet;
}

void DecodedMbufVideoSender::StopSendStreamThread()
{
    for (uint32_t i = g_start_chn_num; i < g_start_chn_num + g_chn_num; i++) {
        g_send_exit_state[i] = 1;
    }
    g_exit = 1;
}

void DecodedMbufVideoSender::StopGetPicThread()
{
    for (uint32_t i = g_start_chn_num; i < g_start_chn_num + g_chn_num; i++) {
        g_get_exit_state[i] = 1;
        g_send_exit_state[i] = 1;
    }
    g_exit = 1;
}

